import time
import poplib
import smtplib
from email.header import decode_header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr

# 通用的邮件发送服务，禁止从这里读取配置等。参数请从外部传入

# user为发送者
def send(smtp, send_user, mailto, title, msg=None, file_name=None):
    msg_root = MIMEMultipart('related')
    msg_root['From'] = formataddr(["EmailPC_Server", send_user])
    msg_root['To'] = formataddr([mailto, mailto])
    msg_root['Subject'] = title
    if msg is not None:
        msg_text = MIMEText('%s' % msg, 'html', 'utf-8')
        msg_root.attach(msg_text)
    if file_name is not None:
        att = MIMEText(open('%s' % file_name, 'rb').read(), 'base64', 'utf-8')
        att["Content-Type"] = 'application/octet-stream'
        att["Content-Disposition"] = 'attachment; filename="%s"' % file_name
        msg_root.attach(att)

    try_num = 0
    try_max = 3
    while try_num < try_max:
        try_num += 1
        try:
            smtp.sendmail(send_user, mailto, msg_root.as_string())
            return True
        except Exception as result:
            time.sleep(2)
            print(result)


def get_smtp(smtp_server, smtp_port):
    try:
        # 绝大多数邮箱不开启加密时的SMTP端口为25
        if smtp_port == '25':
            smtp = smtplib.SMTP(smtp_server, smtp_port)
        # 587端口常用作TLS加密
        elif smtp_port == '587':
            smtp = smtplib.SMTP(smtp_server, smtp_port)
            smtp.ehlo()
            smtp.starttls()
            smtp.ehlo()
        else:
            smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
        return smtp
    except Exception as result:
        print(result)


def get_smtp_login(smtp_server, smtp_port, user, pwd):
    try:
        smtp = get_smtp(smtp_server, smtp_port)
        if smtp is not None:
            smtp.login(user, pwd)
            return smtp
    except Exception as result:
        print(result)


def get_pop_connect(pop_server, pop_port):
    # 绝大多数邮箱不开启加密时的POP端口为110
    if pop_port == '110':
        return poplib.POP3(pop_server, pop_port, timeout=5)
    else:
        return poplib.POP3_SSL(pop_server, pop_port, timeout=5)


def get_pop_login(pop, user, pwd):
    if pop is not None:
        pop.user(user)
        # 设置密码时，会验证密码，错误则抛出异常
        pop.pass_(pwd)
        return pop


# 解决邮件中的编码问题
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value


# 获取邮件的编码信息
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos + 8:].strip()
    return charset


def get_info(msg, indent=0):
    subject = ''
    addr = ''
    content = ''
    if indent == 0:
        for header in ['From', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header == 'Subject':
                    subject = decode_str(value)
                else:
                    hdr, addr = parseaddr(value)
    if msg.is_multipart():
        parts = msg.get_payload()
        for n, part in enumerate(parts):
            content_value = get_info(part, indent + 1)[2]
            if content_value != '':
                content = content_value
    else:
        content_type = msg.get_content_type()
        if content_type == 'text/plain':
            content = msg.get_payload(decode=True)
            charset = guess_charset(msg)
            if charset:
                content = content.decode(charset)
        else:
            content = ''
    return subject, addr, content
